package com.royal.lr.util;

import com.alibaba.fastjson.JSONObject;
import com.royal.lr.netty.NettyHttpServerHandler;
import org.apache.http.*;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.w3c.dom.Document;

import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.*;
import java.net.*;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;


public class HttpUtil {

	private static final Logger LOGGER = LogManager.getLogger(HttpUtil.class);

	private static CloseableHttpClient httpClient;
	private static final Integer REQ_TIMEOUT = 60000;     //请求超时时间ms
	private static final Integer CONN_TIMEOUT = 60000;     //连接超时时间ms
	private static final Integer SOCK_TIMEOUT = 60000;    //读取超时时间ms
	private static  String ip="116.62.194.248";
	private static  int port=3128;

	static {
        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
        cm.setMaxTotal(50000);
        cm.setDefaultMaxPerRoute(500);
		RequestConfig requestConfig = RequestConfig.custom()
				.setConnectionRequestTimeout(REQ_TIMEOUT)
				.setConnectTimeout(CONN_TIMEOUT).setSocketTimeout(SOCK_TIMEOUT)
				.build();
		HttpRequestRetryHandler requestRetryHandler=new HttpRequestRetryHandler() {
			public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
				if (executionCount > 3) //超过重试次数，就放弃
					return false;
				if (exception instanceof NoHttpResponseException) {//没有响应，重试
					return true;
				}else if (exception instanceof ConnectTimeoutException) {//连接超时，重试
					return true;
				} else if (exception instanceof SocketTimeoutException) {//连接或读取超时，重试
					return true;
				}else if (exception instanceof SSLHandshakeException) {//本地证书异常
					return false;
				} else if (exception instanceof InterruptedIOException) {//被中断
					return false;
				} else if (exception instanceof UnknownHostException) {//找不到服务器
					return false;
				}  else if (exception instanceof SSLException) {//SSL异常
					return false;
				} else {
					LOGGER.error("未记录的请求异常：" + exception.getClass());
				}
				HttpClientContext clientContext = HttpClientContext.adapt(context);
				HttpRequest request = clientContext.getRequest();
				// 如果请求是幂等的，则重试
				if (!(request instanceof HttpEntityEnclosingRequest)) return true;
				return false;
			}
		};

		httpClient = HttpClients.custom().setConnectionManager(cm).setDefaultRequestConfig(requestConfig).setRetryHandler(requestRetryHandler).build();
		LOGGER.info("---------------------totalStats:{}", cm.getTotalStats());

	}

    public static String get(String url) {
        CloseableHttpResponse response = null;
		HttpGet httpGet=null;
        BufferedReader in = null;
        String result = "";
        try {
             httpGet = new HttpGet(url);
            RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(60000).setConnectionRequestTimeout(60000).setSocketTimeout(60000).build();
            httpGet.setConfig(requestConfig);
            httpGet.addHeader("Content-type", "application/json; charset=utf-8");
            httpGet.setHeader("Accept", "application/json");
            response = httpClient.execute(httpGet);
            in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
            StringBuffer sb = new StringBuffer("");
            String line = "";
            String NL = System.getProperty("line.separator");
            while ((line = in.readLine()) != null) {
                sb.append(line + NL);
            }
            in.close();
            result = sb.toString();
        } catch (Exception e) {
			httpGet.abort();
            e.printStackTrace();
        } finally {
			close(httpGet,null,in,response);
        }
        return result;
    }




	public static String getZip(String url) {
		CloseableHttpResponse response = null;
		BufferedReader in = null;
		HttpGet httpGet =null;
		String result = "";
		try {
			 httpGet = new HttpGet(url);
			RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(60000).setConnectionRequestTimeout(60000).setSocketTimeout(60000).build();
			httpGet.setConfig(requestConfig);
			httpGet.setConfig(requestConfig);
			httpGet.addHeader("Content-type", "application/json; charset=utf-8");
			httpGet.setHeader("Accept", "application/json");
			httpGet.setHeader("Content-Encoding", "gzip");
			httpGet.setHeader("Transfer-Encoding", "chunked");
			response = httpClient.execute(httpGet);
			InputStream is=response.getEntity().getContent();
			is= new GZIPInputStream(is);
			in = new BufferedReader(new InputStreamReader(is));
			//in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
			StringBuffer sb = new StringBuffer("");
			String line = "";
			String NL = System.getProperty("line.separator");
			while ((line = in.readLine()) != null) {
				sb.append(line + NL);
			}
			in.close();
			result = sb.toString();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			close(httpGet,null,in,response);
		}
		return result;
	}


    public static String post(String url, String jsonString)throws Exception {
        CloseableHttpResponse response = null;
        BufferedReader in = null;
        String result = "";
		HttpPost httpPost =null;
        try {
             httpPost = new HttpPost(url);
            httpPost.addHeader("Content-type", "application/json; charset=utf-8");
            httpPost.setHeader("Accept", "application/json");
            httpPost.setEntity(new StringEntity(jsonString, Charset.forName("UTF-8")));
            response = httpClient.execute(httpPost);
			HttpEntity entity =response.getEntity();
			if(entity!=null) {
				result = EntityUtils.toString(entity);
			}
        } catch (Exception e) {
        	httpPost.abort();
        	throw e;
        } finally {
			close(null,httpPost,in,response);
        }
        return result;
    }


	public static String delete(String url)throws Exception {
		CloseableHttpResponse response = null;
		BufferedReader in = null;
		String result = "";
		HttpDelete httpDelete =null;
		try {
			httpDelete = new HttpDelete(url);
			httpDelete.addHeader("Content-type", "application/json; charset=utf-8");
			response = httpClient.execute(httpDelete);
			HttpEntity entity =response.getEntity();
			if(entity!=null) {
				result = EntityUtils.toString(entity);
			}
		} catch (Exception e) {
			httpDelete.abort();
			throw e;
		} finally {
			try {
				if(httpDelete!=null){
					httpDelete.releaseConnection();
				}
				if(in!=null){
					in.close();
				}
				if (null != response) {
					response.close();
					EntityUtils.consume(response.getEntity());
				}
			} catch (Exception e) {
				throw e;
			}
		}
		return result;
	}
	public static String postZip(String url, String jsonString) {
		CloseableHttpResponse response = null;
		BufferedReader in = null;
		HttpPost httpPost =null;
		String result = "";
		try {
			ByteArrayOutputStream originalContent = new ByteArrayOutputStream();
			originalContent
					.write(jsonString.getBytes(Charset.forName("UTF-8")));
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			GZIPOutputStream gzipOut = new GZIPOutputStream(baos);
			originalContent.writeTo(gzipOut);
			gzipOut.finish();
			 httpPost = new HttpPost(url);
			RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(30000).setConnectionRequestTimeout(30000).setSocketTimeout(30000).build();
			httpPost.setConfig(requestConfig);
			httpPost.setConfig(requestConfig);
			httpPost.addHeader("Content-type", "application/json; charset=utf-8");
			httpPost.setHeader("Accept", "application/json");
			httpPost.setHeader("Content-Encoding", "gzip");
			httpPost.setEntity(new ByteArrayEntity(baos.toByteArray()));
			response = httpClient.execute(httpPost);
			in = new BufferedReader(new InputStreamReader(new GZIPInputStream(response.getEntity().getContent())));
			StringBuffer sb = new StringBuffer("");
			String line = "";
			String NL = System.getProperty("line.separator");
			while ((line = in.readLine()) != null) {
				sb.append(line + NL);
			}
			in.close();
			result = sb.toString();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			close(null,httpPost,in,response);
		}
		return result;
	}




	public static String convertStreamToString(InputStream is) throws UnsupportedEncodingException {

		BufferedReader reader = new BufferedReader(new InputStreamReader(is, "utf-8"));

		StringBuilder sb = new StringBuilder();

		String line = null;

		try {

			while ((line = reader.readLine()) != null) {

				sb.append(line);

			}

		} catch (IOException e) {

			e.printStackTrace();

		} finally {

			try {

				is.close();

			} catch (IOException e) {

				e.printStackTrace();

			}

		}

		return sb.toString();

	}

	 /**
	   * 从远程URL下载文件到本地保存
	   *
	 * @param remoteUrl
	 * @param savePath
	 * @throws IOException
	 */
	public static void downloadNet(String remoteUrl,String savePath) throws MalformedURLException,FileNotFoundException,IOException {
	        // 下载网络文件
	        int bytesum = 0;//记录文件大小
	        int byteread = 0;

	        InputStream inStream=null;
	        FileOutputStream fs=null;
	        try {
	        	URLConnection conn = new URL(remoteUrl).openConnection();
	            inStream = conn.getInputStream();
	            fs = new FileOutputStream(savePath);

	            byte[] buffer = new byte[1204];
	            while ((byteread = inStream.read(buffer)) != -1) {
	                bytesum += byteread;
	                fs.write(buffer, 0, byteread);
	            }
	            //LOGGER.error("文件下载成功！下载地址：{}，存放文件名称：{}，文件大小：{} k",remoteUrl,savePath,bytesum/1024);
			} catch (MalformedURLException e) {
				// TODO Auto-generated catch block
				LOGGER.error("远程URL路径格式错误！{}",remoteUrl);
				throw new MalformedURLException();
	        } catch (FileNotFoundException e) {
	            LOGGER.error("远程文件不存在！{}",remoteUrl,e);
	            throw new FileNotFoundException();
	        } catch (IOException e) {
	        	LOGGER.error(savePath+"文件{}写入失败！",e);
	        	//throw new IOException();
	        }finally{
	        	if(inStream!=null){
	        		try {
						inStream.close();
					} catch (IOException e) {
						// TODO Auto-generated catch block
						LOGGER.error("关闭下载文件流失败",e);
					}
	        	}
	        	if(fs!=null){
		        	try {
						fs.close();
					} catch (IOException e) {
						// TODO Auto-generated catch block
						LOGGER.error("关闭写入文件流失败",e);
					}
	        	}
	        }
	    }
	
	public static String URLEncoder(JSONObject json){

        StringBuffer req = new StringBuffer();
        try {
            String encode = URLEncoder.encode(json.toJSONString(), "UTF-8");
            req.append("?reqData=" +encode);
        } catch (UnsupportedEncodingException e){
            req.append("?reqData=");
        }

        return req.toString();
}

	public static List<NameValuePair> execute(Map<String, String> reqMap) {
		List<NameValuePair> data=new ArrayList<>(reqMap.keySet().size());
		Set<String> keySet = reqMap.keySet();
		for(String key:keySet){
			data.add(new BasicNameValuePair(key,reqMap.get(key)));
		}
		return data;
	}

	public static String postForm(String url, Map<String, String> reqMap) {
		CloseableHttpResponse response = null;
		BufferedReader in = null;
		HttpPost httpPost =null;
		String result = "";
		try {
			 httpPost = new HttpPost(url);
			RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(30000).setConnectionRequestTimeout(30000).setSocketTimeout(30000).build();
			httpPost.setConfig(requestConfig);
			httpPost.setEntity(new UrlEncodedFormEntity(execute(reqMap),Charset.forName("UTF-8")));
			response = httpClient.execute(httpPost);
			in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
			StringBuffer sb = new StringBuffer("");
			String line = "";
			String NL = System.getProperty("line.separator");
			while ((line = in.readLine()) != null) {
				sb.append(line + NL);
			}
			in.close();
			result = sb.toString();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			close(null,httpPost,in,response);
		}
		return result;
	}

	public static String postXml(String url, String jsonString) {
		CloseableHttpResponse response = null;
		BufferedReader in = null;
		String result = "";
		try {
			HttpPost httpPost = new HttpPost(url);
			RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(30000).setConnectionRequestTimeout(30000).setSocketTimeout(30000).build();
			httpPost.setConfig(requestConfig);
			httpPost.setConfig(requestConfig);
			httpPost.addHeader("Content-Type","text/xml");
			httpPost.setEntity(new StringEntity(jsonString, Charset.forName("UTF-8")));
			response = httpClient.execute(httpPost);
			in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
			StringBuffer sb = new StringBuffer("");
			String line = "";
			String NL = System.getProperty("line.separator");
			while ((line = in.readLine()) != null) {
				sb.append(line + NL);
			}
			in.close();
			result = sb.toString();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (null != response) {
					response.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return result;
	}


	public static void close(HttpGet httpGet,HttpPost httpPost,Closeable in,CloseableHttpResponse response){
		try {
			if(httpGet!=null){
				httpGet.releaseConnection();
			}
			if(httpPost!=null){
				httpPost.releaseConnection();
			}
			if(in!=null){
				in.close();
			}
			if (null != response) {
				response.close();
				EntityUtils.consume(response.getEntity());
			}
		} catch (Exception e) {
			LOGGER.error("http 请求关闭异常：",e);
		}
	}
}
